/*
 * $Id: Util.java 3 2007-12-07 01:24:30Z rasan.rasch $
 *
 * Copyright (c) 2002-2006 UC Regents
 * 
 * Permission to use, copy, modify, distribute, and sell this software and
 * its documentation for any purpose is hereby granted without fee, provided
 * that (i) the above copyright notices and this permission notice appear in
 * all copies of the software and related documentation, and (ii) the names
 * of the UC Regents and the University of California are not used in any
 * advertising or publicity relating to the software without the specific,
 * prior written permission of the University of California.
 * 
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY
 * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY
 * THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE
 * OR PERFORMANCE OF THIS SOFTWARE.
 */

package org.cdl.noid;

import java.io.*;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.regex.*;
import java.text.DecimalFormat;

/** 
 * The Util class contains miscellaneous utility functions
 * for manipulating text and file IO.
 *
 * @author  Rasan Rasch
 @ @version $Revision: 3 $
 */
public class Util {

	/** 
	 * If input string is non-null, return value of input, otherwise
	 * return the empty string.
	 * 
	 * @param  str 
	 * @return if <code>str</code> is non-null, value of
	 *         <code>input<code>; empty string otherwise
	 */
	public static String valueOrEmpty(String str) {
		return str != null ? str : "";
	}

	/**
	 * @param s 
	 */
	public static String unNullify(String s) {
		return Util.isEmpty(s) ? "" : s;
	}
	
	/**
	 * Tests whether a string is empty or null.
	 *
	 * @param s string to be tested
	 * @return  <code>true</code> if string is empty or null;
	 *          <code>false</code>  otherwise
	 */
	public static boolean isEmpty(String s) {
		return s == null || s.length() == 0;
	}

	/** 
	 * Tests whether an array is empty or null.
	 * 
	 * @param array array to be tested
	 * @return      <code>true</code> if array is empty or null;
	 *              <code>false</code>  otherwise
	 */
	public static boolean isEmpty(Object[] array) {
		return array == null || array.length == 0;
	}

	/** 
	 * Joins the values of a string array into a single string
	 * where each value separated by the specified delimiter.
	 * 
	 * @param delim delimiter used to separate array values
	 * @param args  array to be joined
	 * @return      newly joined String value
	 */
	public static String join(String delim, String[] args) { 
		StringBuffer result = new StringBuffer();
		int len = args.length;
		for (int i = 0; i < len; i++) { 
			result.append(args[i]);
			if (i < len - 1) {
				result.append(delim);
			}
		} 
		return result.toString();
	}

	/** 
	 * Returns elements of an array matching specfied regular expression.
	 *
	 * @param regexp pattern to test each array member
	 * @param args   array of strings to evaluate the regexp
	 * @return       array of elements that matched <code>regexp</code>
	 */
	public static String[] grep(String regexp, String[] args) {
		ArrayList<String> list = new ArrayList<String>();
		Pattern patt = Pattern.compile(regexp);
		Matcher matcher = patt.matcher("");
		for (int i = 0; i < args.length; i++) {
			matcher.reset(args[i]);
			if (matcher.find()) {
				list.add(args[i]);
			}
		}
		String[] matches = (String[])list.toArray(new String[0]);
		return matches;
	}

	/** 
	 * Tests to see if any element of an array matches specified
	 * regular expression.
	 * 
	 * @param regexp pattern to be evaluated
	 * @param args   array of strings to evaluate the regexp
	 * @return       <code>true</code> if at least one element of
	 *               <code>args</code> matches; <code>false</code>
	 *               otherwise
	 */
	public static boolean grep2(String regexp, String[] args) {
		Pattern patt = Pattern.compile(regexp);
		Matcher matcher = patt.matcher("");
		for (int i = 0; i < args.length; i++) {
			matcher.reset(args[i]);
			if (matcher.find()) {
				return true;
			}
		}
		return false;
	}

	/** 
	 * Returns hostname of system.
	 * 
	 * @return hostname
	 */
	public static String getHostName() {
		String hostName = null;
		try {
			InetAddress localMachine = InetAddress.getLocalHost(); 
			hostName = localMachine.getHostName();
		} catch (java.net.UnknownHostException uhe) {
            // handle exception
			uhe.printStackTrace();
		}
		return hostName;
	}
	
	/** 
	 * Removes first element of an <code>ArrayList</code> and returns
	 * that element.
	 * 
	 * @param list array list to be shifted
	 * @return     first element of array list if it's size is at
	 *             least 1; <code>null</code> otherwise
	 */
	public static Object shift(ArrayList list) {
		return list.size() > 0 ? list.remove(0) : null;
	}

	/** 
	 * Returns current working directory
	 * 
	 * @return path of current working directory; if there was an
	 *         IO error, it will return <code>null</code>
	 */
	public static String getCwd() {
		String cwd = null;
		try {
			cwd = new File(".").getCanonicalPath();
		} catch (IOException e) {
			// handle exception
			e.printStackTrace();
		}
		return cwd;
	}

	/** 
	 * Returns the contents of a file as string.
	 * 
	 * @param fileName file to be read
	 * @return         string containing contents of file
	 */
	public static String getFile(String fileName) {
		StringBuffer sb = new StringBuffer();
		try {
			BufferedReader in =
				new BufferedReader(new FileReader(fileName));
			String str;
			while ((str = in.readLine()) != null) {
				sb.append(str);
			}
			in.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return sb.toString();
	}
	
	/** 
	 * Tests whether an input string matches a pattern.
	 * 
	 * @param pattern regular expression used to test string input
	 * @param input   input string
	 * @return        <code>true</code> if pattern matches;
	 *                <code>false</code> otherwise
	 */
	public static boolean matches(String pattern, String input) {
		return Pattern.compile(pattern).matcher(input).find();
	}

	/** 
	 * Pad integer with leading zeros.
	 * 
	 * @param value  integer value to be padded
	 * @param length minimum length of padded string
	 * @return       zero-padded string
	 */
	public static String zeroPad(int value, int length) {
		// DecimalFormat df = new DecimalFormat("00");
		DecimalFormat df = new DecimalFormat();
		df.setMinimumIntegerDigits(length);
		// df.setGroupingUsed(false);
		return df.format(value);
	}

	/** 
	 * Sets string buffer to <code>newValue</code> string.
	 * 
	 * @param sb       string buffer to be set
	 * @param newValue new value of string buffer
	 */
	public static void setBuffer(StringBuffer sb, String newValue) {
		sb.setLength(0);
		sb.append(newValue);
	}

	/** 
	 * Deletes all files and subdirectories under dir.
	 * Returns true if all deletions were successful.
	 * If a deletion fails, the method stops attempting
	 * to delete and returns false.
	 * 
	 * @param  dir 
	 * @return <code>true</code> if directory was successfully deleted;
	 *         <code>false</code> otherwise
	 */
	public static boolean deleteDir(File dir) {
		if (dir.isDirectory()) {
			String[] children = dir.list();
			for (int i=0; i<children.length; i++) {
				boolean success = deleteDir(new File(dir, children[i]));
				if (!success) {
					return false;
				}
			}
		}
	
		// The directory is now empty so delete it
		return dir.delete();
	}

	/** 
	 * Create a minter with a short term using the specified template. 
	 * 
	 * @param  templ  template for minter
	 * @return        newly created minter
	 * @see    Noid
	 */
	private static Noid createShort(String templ) {
		File noidDir = new File("dbnoid");

		if (noidDir.isDirectory()) {
			if (!deleteDir(noidDir)) {
				System.err.println("can't delete dbnoid directory");
				System.exit(1);
			}
		}

		String term = "short";
		String naan = null;
		String naa = null;
		String subnaa = null;

		Noid noid = new Noid("rasan", ".");
		
		noid.dbCreate(templ, term, naan, naa, subnaa);
		
		return noid;
	}

	/** 
	 * Executes the specified command in a separate process.
	 * 
	 * @param command command to run
	 * @return        <code>true</code> if command exited with a
	 *                zero status; <code>false</code>
	 */
	public static boolean doExec(String command) {
		boolean success = false;
		try {
			Process child = Runtime.getRuntime().exec(command);
			success = child.exitValue() == 0;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return success;
	}

	/** 
	 * Executes the specified command in a separate process and
	 * saves it's output in an <code>ArrayList</code>.  Each
	 * element of the list will correspond to a line of ouput.
	 * Newlines will be stripped from each line.
	 * 
	 * @param command command to be run
	 * @param list    list used to store the output of the command
	 * @return        <code>true</code> if command exited with a
	 *                zero status; <code>false</code>
	 */
	public static boolean doExec(String command, ArrayList<String> list) {
		boolean success = false;
		list.clear();
		try {
			// Execute command
			Process child = Runtime.getRuntime().exec(command);
		
			// Get the input stream and read from it
			BufferedReader in = new BufferedReader(
				new InputStreamReader(child.getInputStream()));
			String str;
			while ((str = in.readLine()) != null) {
				list.add(str);
			}
			in.close();

			success = child.exitValue() == 0;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return success;
	}

	/** 
	 * Removes newline sequence from the end of a string if present.
	 * This is similar to the chomp() built-in function in Perl.
	 * 
	 * @param  str input string to modify
	 * @return     string without newline if it were there; otherwise
	 *             value of original input
	 */
	public static String chomp(String str) {
		if (str.endsWith("\r\n")) {
			return str.substring(0, str.length() - 2);
		}
		if (str.endsWith("\r") || str.endsWith("\n")) {
			return str.substring(0, str.length() - 1);
		}
		return str;
	}

	// http://www.javalobby.org/forums/thread.jspa?threadID=16906&tstart=0
	/** 
	 * Return ordinal suffix for a number.
	 * 
	 * @param  value number
	 * @return       <code>"st", "nd", "rd", or, "th"</code>
	 */
	public static String getOrdinalFor(int value) {
		int hundredRemainder = value % 100;
		int tenRemainder = value % 10;
// 		if (hundredRemainder >= 10 && hundredRemainder <= 20) {
		if (hundredRemainder - tenRemainder == 10) {
			return "th";
 		}
		switch (tenRemainder) {
			case 1:
				return "st";
			case 2:
				return "nd";
			case 3:
				return "rd";
			default:
				return "th";
		}
	}

	/**
	 * Store the contents of <code>buf</code> in a new file.
	 *
	 * @param  fileName path of file to create
	 * @param  buf      contents of file
	 * @return <code>true</code> if file was successfully create;
	 *         <code>false</code> otherwise
	 */
	public static boolean storeFile(String fileName, String buf) {
		//First open the file you want to write into
		try {
			FileOutputStream fout =  new FileOutputStream(fileName);
			
			// now convert the FileOutputStream into a PrintStream
			PrintStream myOutput = new PrintStream(fout);

			// Now you're able to use println statements just 
			// as if you were using System.out.println
			// to write to the terminal
			myOutput.println(buf);
		} catch (IOException e) {
			System.out.println("Error opening file: " + e);
			System.exit(1);
		}
		//sys.chmod(fileName);
		return true;
	}

	public static void bprint(PrintStream out, String s) {
		s = s.replaceAll("\n", "\n ");
		out.println(s);
	}

}
